// Implementation of the HTTP worker pool with WinInet
// Copyright 2006 (C) Ralph Thomas

#include <model/http/httpModel.h>
#include <util/thread.h>
#include <model/error.h>
#include <windows.h>
#include <wininet.h>

namespace model {
	class httpWorker : public util::thread::work {
		std::string	_url;	///< URL to fetch data from.
		httpModel*	_mod;	///< Model to fill with data.
		void error() {
			_mod->setAttribute( kError, adobe::value_t( 6 ) );
		}
	  public:
		httpWorker( const std::string& url, const httpModel* mod ) {
			_url = url;
			_mod = static_cast<httpModel*>( mod->retain() );
		}
		virtual ~httpWorker() {
			if( _mod ) _mod->release();
		}
		virtual void doWork() {
			//
			// Open our session.
			// XXX: do we lose cookies when we destroy the session?
			//
			HINTERNET session( InternetOpen( "Mission",
				INTERNET_OPEN_TYPE_PRECONFIG, "", "", 0 ) );
			if( !session ) { error(); return; }
			//
			// Open the target URL. Note that this will open
			// anything Windows understands (including https and
			// even FTP!).
			//
			HINTERNET http( InternetOpenUrl( session, _url.c_str(),
				"", 0, INTERNET_FLAG_NO_UI, 0 ) );
			if( !http ) {
				InternetCloseHandle( http );
				error(); return;
			}
			//
			// Extract the read data from the http handle.
			//
			std::string	read;
			DWORD		bytesRead;
			char		buf[1024];
			do {
				if( InternetReadFile( http, &buf, 1024,
					&bytesRead ) ) {
					read += std::string( buf, bytesRead );
				}
			} while( bytesRead );
			//
			// Now extract the MIME type of the data.
			//
			std::string	type;
			bytesRead = 1024;
			if( HttpQueryInfo( http, HTTP_QUERY_CONTENT_TYPE,
				buf, &bytesRead, NULL ) ) {
				type = std::string( buf, bytesRead );
			}
			//
			// Close up the connection and our session handles.
			//
			InternetCloseHandle( http );
			InternetCloseHandle( session );
			//
			// Set our data and MIME type into the model.
			//
			_mod->load( type, read );
		}
		virtual priority getPriority() const {
			return kWorkPriorityRegular;
		}
	};
	static util::thread* worker = 0;
	void httpFetch( const httpModel* mod, const std::string& theUrl ) {
		if( !mod ) return;
		if( theUrl.empty() ) return;
		//
		// Create the thread now if it hasn't already been created.
		// Only the main thread enters this function, so there's no
		// race condition on creating the thread.
		//
		if( !worker ) worker = new util::thread();
		worker->adoptWork( new httpWorker( theUrl, mod ) );
	}
};

